import { ClientMessage } from "@runtime/generate/message/ClientMessage";
import WebSocketComponent from "@runtime/module/WebSocket/WebSocketComponent";
import { reactive, Ref, ref, UnwrapNestedRefs, watch, WatchStopHandle } from "vue";
import HighlighterComponent from "./HighlighterComponent";

/**
 * 标签组件
 */
export default class LabelComponent {
    private static instance: LabelComponent = new LabelComponent();
    /**
     * 标签组件
     */
    public static get Default(): LabelComponent {
        return this.instance;
    }

    constructor() {
        window.addEventListener('unload', this.Dispose.bind(this));

        this.watchStopHandles.push(watch(this.Highlighters, this.OnHighlightersChangedAsync.bind(this)));
    }

    Dispose() {
        window.removeEventListener('unload', this.Dispose);

        for (const watchStopHandle of this.watchStopHandles) {
            watchStopHandle();
        }
        this.watchStopHandles.clear();
    }

    private watchStopHandles: Array<WatchStopHandle> = [];

    private informations: UnwrapNestedRefs<Map<number, ClientMessage.LabelInformation>> = reactive(new Map());

    /**
     * Count
     */
    public get Count(): number {
        return this.informations.size;
    }

    /**
     * Informations
     */
    public get Informations(): UnwrapNestedRefs<Map<number, ClientMessage.LabelInformation>> {
        return this.informations;
    }

    /**
     * 高亮物体InstanceId
     */
    public Highlighters: Ref<Array<number>> = ref([]);

    /**
     * 当前高亮物体发生改变
     * @param highlighters 高亮物体InstanceId
     */
    private async OnHighlightersChangedAsync(highlighters: Array<number>): Promise<void> {
        await HighlighterComponent.Default.UpdateAsync(highlighters);
    }

    public async LoadAsync(instanceId: number): Promise<boolean> {
        const response: ClientMessage.LabelLoadResponse = await WebSocketComponent.Default.PostMessageAsync(new ClientMessage.LabelLoadRequest(instanceId));

        // 引导线长度计算
        const fontSize = getComputedStyle(window.document.documentElement).fontSize;
        const factor = Number.parseFloat(fontSize.substring(0, fontSize.length - 1));
        for (const information of response.Informations) {
            information.Length = information.Length / factor;
        }

        // 更新引导线
        this.informations.clear();
        for (const information of response.Informations) {
            this.informations.set(information.InstanceId, information);
        }

        return response.Error == 0;
    }

    public Update(input: ClientMessage.LabelUpdateInformation): boolean {
        const information = this.informations.get(input.InstanceId);
        if (information == undefined) {
            return false;
        }

        information.ViewportPointX = input.ViewportPointX;
        information.ViewportPointY = input.ViewportPointY;
        information.Version++;
        return true;
    }

    public Remove(instanceIds: Array<number>): void {
        if (instanceIds.length == 0) {
            window.Logger.Warning(`标签移除数组为空`);
            return;
        }
        WebSocketComponent.Default.PostMessage(new ClientMessage.LabelRemoveMessage(instanceIds));
    }

    public Clear(): void {
        WebSocketComponent.Default.PostMessage(new ClientMessage.LabelClearMessage());
        this.informations.clear();
        this.Highlighters.value.clear();
    }
}